package com.twenty.seven.toolbox.encrypt.rsa;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author 001
 * @Date 2020/1/7 13:37
 * @TODO RSA公钥/私钥/签名工具包
 **/
public class RSAUtils {

    /**
     * RSA算法加密
     */
    private static final String KEY_ALGORITHM = "RSA";

    /**
     * 签名算法
     */
    private static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    /**
     * 公钥
     */
    public static final String PUBLIC_KEY = "RSAPublicKey";

    /**
     * 私钥
     */
    public static final String PRIVATE_KEY = "RSAPrivateKey";


    /**
     * 生成密钥对，公钥和私钥
     *
     * @return RSAPrivateKey 私钥，RSAPublicKey公钥
     * @throws Exception
     */
    public static Map<String, Object> genKeyPair() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //1024 有点长
        keyPairGenerator.initialize(512);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> map = new HashMap<>();
        map.put(PRIVATE_KEY, privateKey);
        map.put(PUBLIC_KEY, publicKey);
        return map;
    }

    /**
     * 用私钥对信息生成数字签名
     *
     * @param data       已加密的数据
     * @param privateKey 私钥
     * @return
     */
    public static String sign(String data, String privateKey) throws Exception {
        byte[] dataContent = Base64.decodeBase64(data);
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey pk = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(pk);
        signature.update(dataContent);
        return Base64.encodeBase64String(signature.sign());
    }

    /**
     * 校验数字签名
     *
     * @param data      已加密数据
     * @param publicKey 公钥
     * @param sign      数字签名
     * @return
     * @throws Exception
     */
    public static boolean verify(String data, String publicKey, String sign) throws Exception {
        byte[] dataContent = Base64.decodeBase64(data);
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey pk = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pk);
        signature.update(dataContent);
        return signature.verify(Base64.decodeBase64(sign));
    }

    /**
     * <p>
     * 获取私钥
     * </p>
     *
     * @param keyMap 密钥对
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap) {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return Base64.encodeBase64String(key.getEncoded());
    }

    /**
     * <p>
     * 获取公钥
     * </p>
     *
     * @param keyMap 密钥对
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap) {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return Base64.encodeBase64String(key.getEncoded());
    }

    /**
     * <p>
     * 2.私钥加密、公钥解密 ---- 加密
     * </p>
     *
     * @param d          源数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static String encryptByPrivateKey(String d, String privateKey)
            throws Exception {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey pk = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, pk);
        byte[] result = cipher.doFinal(d.getBytes());
        return Base64.encodeBase64String(result);
    }

    /**
     * <p>
     * .私钥加密、公钥解密 ---- 解密
     * </p>
     *
     * @param data      已加密数据
     * @param publicKey 公钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static String decryptByPublicKey(String data, String publicKey)
            throws Exception {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey pk = keyFactory.generatePublic(x509EncodedKeySpec);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, pk);
        byte[] result = cipher.doFinal(Base64.decodeBase64(data));
        return new String(result);
    }

    /**
     * <P>
     * 私钥解密、公钥加密 ---- 解密
     * </p>
     *
     * @param data       已加密数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static String decryptByPrivateKey(String data, String privateKey)
            throws Exception {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        KeyFactory keyFactory5 = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey5 = keyFactory5.generatePrivate(pkcs8EncodedKeySpec5);
        Cipher cipher5 = Cipher.getInstance(KEY_ALGORITHM);
        cipher5.init(Cipher.DECRYPT_MODE, privateKey5);
        byte[] result5 = cipher5.doFinal(Base64.decodeBase64(data));
        return new String(result5);
    }


    /**
     * <p>
     * 公钥加密、私钥解密 ---- 加密
     * </p>
     *
     * @param d         源数据
     * @param publicKey 公钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static String encryptByPublicKey(String d, String publicKey)
            throws Exception {
        X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        KeyFactory keyFactory2 = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey2 = keyFactory2.generatePublic(x509EncodedKeySpec2);
        Cipher cipher2 = Cipher.getInstance(KEY_ALGORITHM);
        cipher2.init(Cipher.ENCRYPT_MODE, publicKey2);
        byte[] result2 = cipher2.doFinal(d.getBytes());
        return Base64.encodeBase64String(result2);
    }


    public static void main(String[] args) throws Exception {
        String puk = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCKkwNjOeAtq2qmJovzzEWJyARDwmmM6oCWwph3kUmqq55Ul+VmgUgdJV+X8M6V8sGPdwy8FGB58kB3zx8eeVzJQpqCI6aA2LMlKkaUEG6TUEMnYkmvhNtMd9k4YCnNtiLLWJ1S/e6UQkDsOkhfCnzA5Ac3VUfLAGEAkKgeE4NayQIDAQAB";
        String prk = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIqTA2M54C2raqYmi/PMRYnIBEPCaYzqgJbCmHeRSaqrnlSX5WaBSB0lX5fwzpXywY93DLwUYHnyQHfPHx55XMlCmoIjpoDYsyUqRpQQbpNQQydiSa+E20x32ThgKc22IstYnVL97pRCQOw6SF8KfMDkBzdVR8sAYQCQqB4Tg1rJAgMBAAECgYBTVihiYyr7rCweMe5WtxFW1BAkg+WgVmLwx6STu69W0ZENhK/0Hmm1BYXgxXQn328ijVD+Ry7iB5tXshsf45K1n7kxblAv/WnRbrX4pymbRj3ejf1UWAeQ5rKn+r4nTHkrg10he+lQK9Z+Wf4k/6XiUp1IBw/U8u+3RVPsbgCVJQJBAMh9y+EBXWrwQpw+LSzcev3a8qPsiY89uLrNS8+0Z0NjEm0xsV8ZB7tsxHY1dINQmV+ifNu/VG+lM0eQmkQSrEcCQQCw8LmC3eR8NvAWbpB9l62a1DR8Fh0BrYyuziLeesCHGinKswdjiiuTmcfaVizaYoA6G+y6DvfX3Als5jeMnBhvAkBl9EqsZlRKIFnPOHMioBBPbXr8Tzn4xKtfGy0VN6lXhFcHfkCzmnfrILmbXz2b1W3ZSzjxSo+2oqy8FNXODizbAkAiV5ap/8dJFKCkufDxb28Sjf1h2CjpGnYjt36tD8YucrWJ0hWtDDRJAZ/4kKFEAbpBjQn1UtJn4x0xNb2yXNmhAkBcroOZI2f4cASEZcMtyW5yIpovynWZ84Wi59S8SHevOr21lDt0idV9OIu+7Vo7kQIck6sk4Z2Ve/1mHMlCaOl+";
//        String sign = RSAUtils.sign("hhhhhhh","MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKIOM4uBlKePngZUPpEQjfOdBW2aC5DdVT4V+GIh13D1bNzKNvTlbiqlmZhlGKw77pndN0wuX6LPBpGd928/hnh8Jv9gPTkK/JxCwzj+yMH7t2IFRZ2+gHwuDHfke5AbGl8Mvde4eOX/JLN7O8mHrukpmEuG9b3dqWS+Mh/5ERvnAgMBAAECgYAM1Br4fDWMXi4gSiL50Nmr404+sucffKX22D5lZlBrvMH1aHyZPmBON/XEvpwJZmUpAP4TpcgkV0cp19tyjxDR8En3/ph50qkJcpLecgROFlHy0b85DbT1sUSbWbCo53EF49Ame84YiVku+rhEXvk8gx/DpBsb/rTDDwMTpOrhwQJBAOvMLqSBCRsmPUQ0Nbjt4E5wYEWJ0FPAy4Gt9u+XMncgVU2pZZ5Qo7MVGKigpz5rTisuZGRe5nMIfTBiLnKGFQkCQQCv8JyY+SgVl8v3b/lcOG8RWLb1H1ckL2+gNzHkT88g0n8lOKZo4fmwcRf3KIB5JdOfqIhmWgs8zKKuE7Xq4lVvAkEAtGDv1Vv4cVJhT8l4x00BaD/DBa8VNNypUTyZSFMrgcG0P8K0P9WERLyAro6nIbLIi3PjzHxkYd8+lUKmMWmssQJAfDJ26QmhQTTpt97kgTQZO36LkJeyFQojW077OjcYeQv+0xCdcBZtAx+ikkeWAW8xZ1g6CT5xBldSU134ojlpowJAAlrEATeC+lr34F6uL3yOn4aBJEfKBvOC/b+eot5vMXAp9DvKlUmLMzqUXpQEdapy0oKAMJZ95fGs+dqXXFSb9w==");
//        Map<String,Object> map = RSAUtils.genKeyPair();
//        System.out.println("private:"+RSAUtils.getPrivateKey(map));
//        System.out.println("public:"+RSAUtils.getPublicKey(map));
//        System.out.println(sign);
//        boolean flag = RSAUtils.verify("hhhhhh","MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiDjOLgZSnj54GVD6REI3znQVtmguQ3VU+FfhiIddw9Wzcyjb05W4qpZmYZRisO+6Z3TdMLl+izwaRnfdvP4Z4fCb/YD05CvycQsM4/sjB+7diBUWdvoB8Lgx35HuQGxpfDL3XuHjl/ySzezvJh67pKZhLhvW93alkvjIf+REb5wIDAQAB",
//                "HeU9bsBViEJwEFQTjTXGh1TcEYIdPbHJPuLvmviLMMFv1FH/OOM0YDLr+YWlMDfZodzXTF15ndURKKFXR0MDTsac7GetGy2EZyBpUMv1oWaW/4x502VBJfdtIovumJwIwxneicTlrgm6LrqzmRKHZZSEH9zfDfjIsYNkD246ijg=");
//        System.out.println(flag);
        String h = "hello,您好!";
        System.out.println("公钥加密，私钥解密：");
        String data = RSAUtils.encryptByPublicKey(h, puk);
        System.out.println("H:" + RSAUtils.decryptByPrivateKey(data, prk));
        System.out.println("私钥加密，公钥解密：");
        String dd = RSAUtils.encryptByPrivateKey(h, prk);
        System.out.println("P:" + RSAUtils.decryptByPublicKey(dd, puk));
        //公钥
        //MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiDjOLgZSnj54GVD6REI3znQVtmguQ3VU+FfhiIddw9Wzcyjb05W4qpZmYZRisO+6Z3TdMLl+izwaRnfdvP4Z4fCb/YD05CvycQsM4/sjB+7diBUWdvoB8Lgx35HuQGxpfDL3XuHjl/ySzezvJh67pKZhLhvW93alkvjIf+REb5wIDAQAB

        //sign
        //HeU9bsBViEJwEFQTjTXGh1TcEYIdPbHJPuLvmviLMMFv1FH/OOM0YDLr+YWlMDfZodzXTF15ndURKKFXR0MDTsac7GetGy2EZyBpUMv1oWaW/4x502VBJfdtIovumJwIwxneicTlrgm6LrqzmRKHZZSEH9zfDfjIsYNkD246ijg=

        //私钥
        //MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKIOM4uBlKePngZUPpEQjfOdBW2aC5DdVT4V+GIh13D1bNzKNvTlbiqlmZhlGKw77pndN0wuX6LPBpGd928/hnh8Jv9gPTkK/JxCwzj+yMH7t2IFRZ2+gHwuDHfke5AbGl8Mvde4eOX/JLN7O8mHrukpmEuG9b3dqWS+Mh/5ERvnAgMBAAECgYAM1Br4fDWMXi4gSiL50Nmr404+sucffKX22D5lZlBrvMH1aHyZPmBON/XEvpwJZmUpAP4TpcgkV0cp19tyjxDR8En3/ph50qkJcpLecgROFlHy0b85DbT1sUSbWbCo53EF49Ame84YiVku+rhEXvk8gx/DpBsb/rTDDwMTpOrhwQJBAOvMLqSBCRsmPUQ0Nbjt4E5wYEWJ0FPAy4Gt9u+XMncgVU2pZZ5Qo7MVGKigpz5rTisuZGRe5nMIfTBiLnKGFQkCQQCv8JyY+SgVl8v3b/lcOG8RWLb1H1ckL2+gNzHkT88g0n8lOKZo4fmwcRf3KIB5JdOfqIhmWgs8zKKuE7Xq4lVvAkEAtGDv1Vv4cVJhT8l4x00BaD/DBa8VNNypUTyZSFMrgcG0P8K0P9WERLyAro6nIbLIi3PjzHxkYd8+lUKmMWmssQJAfDJ26QmhQTTpt97kgTQZO36LkJeyFQojW077OjcYeQv+0xCdcBZtAx+ikkeWAW8xZ1g6CT5xBldSU134ojlpowJAAlrEATeC+lr34F6uL3yOn4aBJEfKBvOC/b+eot5vMXAp9DvKlUmLMzqUXpQEdapy0oKAMJZ95fGs+dqXXFSb9w==
    }

}
